/**
 *
 * 暂时用不到
 *
 */

(function () {
    let Client, Frame, Protocol, Command = {
        CONNECT: 0,
        SUBSCRIBE: 1,
        UNSUBSCRIBE: 2,
        MESSAGE: 3,
        SEND: 4,
        DISCONNECT: 5,
    }, LF = '\n', COLON = ':';

    Frame = (function () {
        function Frame(command, headers, body) {
            this.command = command;
            this.headers = headers || {"content-type": "json"};
            this.body = body || "";
        }

        Frame.sizeOf = function (d) {
            if(d.byteLength) {
                return d.byteLength;
            } else if(d) {
                return encodeURI(d).match(/%..|./g).length;
            } else {
                return 0;
            }
        };

        Frame.prototype.encode = function () {
            let data;

            // 编码命令
            data = Uint8Array.of(Command[this.command]);
            data = concat(null, data, Uint8Array.of(LF.charCodeAt(0)));

            // 编码请求头
            let headers = this.headers, value;
            headers["content-length"] = Frame.sizeOf(this.body);
            for (let key in headers) {
                if (!headers.hasOwnProperty(key)) continue;
                data = concat(null, data, stob(key));
                data = concat(null, data, Uint8Array.of(COLON.charCodeAt(0)));
                data = concat(null, data, stob(headers[key]));
                data = concat(null, data, Uint8Array.of(LF.charCodeAt(0)));
            }
            data = concat(null, data, Uint8Array.of(LF.charCodeAt(0)));

            // 编码请求体
            if(!headers["content-length"]) {
                return data;
            }
            if(this.headers["content-type"] === "json") {
                data = concat(null, data, stob(JSON.stringify(this.body)));
            } else {
                // 如果不指定为json的话，则认为是Uint8Array
                data = concat(null, data, this.body);
            }

            data = concat(null, data, Uint8Array.of(0));

            return data;
        };

        Frame.decode = function(data) {
            let offset = 0;

            // 解码命令
            let command = data[offset++];
            for(let key in Command) {
                if(Command[key] === command) {
                    command = key;
                    break;
                }
            }

            // 跳过换行符
            while(data[offset] === LF.charCodeAt(0)) {
                offset++;
            }

            // 解码请求头
            let headers = {};
            let arr = [];
            while(true) {
                let start = offset;
                while((offset < data.length) && data[offset] !== LF.charCodeAt(0))
                    offset++;
                if(start === offset) {
                    break;
                }

                arr.push(data.slice(start, offset++));
            }
            if(arr.length) {
                for(let i = 0; i < arr.length; ++i) {
                    let colonIndex = arr[i].indexOf(COLON.charCodeAt(0));
                    if(colonIndex === -1) {
                        console.error("请求头格式不对！");
                        return;
                    }
                    let key = btos(arr[i].slice(0, colonIndex));
                    let value = btos(arr[i].slice(colonIndex + 1, arr[i].length));
                    headers[key] = key === "content-length" ? parseInt(value) : value;
                }
            }

            // 跳过换行符
            while(data[offset] === LF.charCodeAt(0)) {
                offset++;
            }

            // 解码请求体
            let body;
            if(headers["content-length"]) {
                body = data.slice(offset, offset + headers["content-length"]);
                offset += headers["content-length"];
            } else {
                body = data.slice(offset, data.length - 1);
                offset += (data.length - 1) - offset;
            }
            // 如果是json字符串，转换成json对象
            if(headers["content-type"] === "application/json") {
                console.log("body => ", btos(body));
                body = JSON.parse(btos(body));
            }

            if(++offset !== data.length) {
                console.error("数据解析异常：offset=%d, data.length=%d", offset, data.length);
                return;
            }

            return new Frame(command, headers, body);
        };

        return Frame;
    })();

    Client = (function () {
        function Client(ws) {
            this.ws = ws;
            this.ws.binaryType = "arraybuffer";
            this.counter = 0;
            this.connected = false;
            this.heartbeat = {
                outgoing: 10000,
                incoming: 10000
            };
            this.maxWebSocketFrameSize = 16 * 1024;
            this.subscriptions = {};
            this.partialData = '';
        }

        Client.prototype._transmit = function(command, headers, body) {
            let out = new Frame(command, headers, body).encode();
            this.ws.send(out);
        };

        Client.prototype.connect = function (headers, connectCallback, errorCallback) {

            return this.ws.onopen = (function (_this) {
                return function () {
                    return _this._transmit("CONNECT", headers);
                }
            })(this);
        };

        Client.prototype.send = function(destination, headers, body) {
            if (headers == null) {
                headers = {};
            }
            if (body == null) {
                body = '';
            }
            headers.destination = destination;
            return this._transmit("SEND", headers, body);
        };

        return Client;
    })();

    Protocol = {
        Frame: Frame,
        client: function(url, protocols) {
            let ws = new WebSocket(url, protocols);
            return new Client(ws);
        },
    };

    window.Protocol = Protocol;

})(window);